home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / csezform / csezform.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-12-22  |  9.7 KB  |  361 lines

  1. unit CSEZForm;
  2. { Copyright 1995 Classic Software
  3.   All Rights Reserved
  4.  
  5.   EZForm classes allow you to create forms
  6.   which can be navigated using the Enter,
  7.   Up/Down Arrow and Ctrl+Tab keys in addition
  8.   to the standard Tab key behaviour.
  9.  
  10.   Individual support for the additional
  11.   navigation keys can be enabled/disabled for
  12.   each form instance.
  13.  
  14.   EZForm enhanced form navigation can be
  15.   enabled or disabled globally; for example,
  16.   in response to a user setting a system
  17.   option.
  18. }
  19.  
  20. interface
  21.  
  22. uses
  23.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  24.   Forms, Dialogs, StdCtrls, DBCtrls, DBGrids, Mask;
  25.  
  26. type
  27.   { Forward declarations }
  28.   TcsEZForm = class;
  29.   TcsEZKeys = class;
  30.   TcsEZFormOptions = class;
  31.  
  32.  
  33.   TNavigationKey = (nkEnter, nkUpDnArrows, nkCtrlTab);
  34.   TNavigationKeys = set of TNavigationKey;
  35.  
  36.   { TcsEZForm }
  37.  
  38.   TcsEZForm = class(TForm)
  39.   private
  40.     FNavigationKeys: TNavigationKeys;
  41.     FOldDefaultBtn: TButton;
  42.     FOldKeyPreview: Boolean;
  43.     FOldOnKeyDown: TKeyEvent;
  44.     FOldOnKeyPress: TKeyPressEvent;
  45.     procedure SetNavigationKeys(Value: TNavigationKeys);
  46.     function FindDefaultBtn: TButton;
  47.     function FindEZKeys: TcsEZKeys;
  48.   protected
  49.     procedure FormKeyDown(Sender: TObject; var Key: Word;
  50.       Shift: TShiftState);
  51.     procedure FormKeyPress(Sender: TObject; var Key: Char);
  52.   public
  53.     constructor Create(AOwner: TComponent); override;
  54.     function CanIntercept(KeyType: TNavigationKey; Ctrl: TControl): Boolean; virtual;
  55.     procedure SelectDefaultBtn; virtual;
  56.     property OldDefaultBtn: TButton read FOldDefaultBtn;
  57.     property OldKeyPreview: Boolean read FOldKeyPreview write FOldKeyPreview;
  58.   published
  59.     property NavigationKeys: TNavigationKeys read FNavigationKeys write SetNavigationKeys
  60.       default [nkEnter, nkUpDnArrows, nkCtrlTab];
  61.   end;
  62.  
  63.   { TcsEZKeys }
  64.  
  65.   TcsEZKeys = class(TComponent)
  66.   private
  67.     FNavigationKeys: TNavigationKeys;
  68.     procedure SetNavigationKeys(Value: TNavigationKeys);
  69.   public
  70.     constructor Create(AOwner: TComponent); override;
  71.   published
  72.     property NavigationKeys: TNavigationKeys read FNavigationKeys write SetNavigationKeys
  73.       default [nkEnter, nkUpDnArrows, nkCtrlTab];
  74.   end;
  75.  
  76.   { TcsEZFormOptions }
  77.  
  78.   TcsEZFormOptions = class(TObject)
  79.   private
  80.     FEnabled: Boolean;
  81.     FDefaultNavigationKeys: TNavigationKeys;
  82.     procedure Enable(Value: Boolean);
  83.     procedure SetDefaultNavigationKeys(Value: TNavigationKeys);
  84.   public
  85.     constructor Create;
  86.     procedure Init; virtual;
  87.     property Enabled: Boolean read FEnabled write Enable;
  88.     property DefaultNavigationKeys: TNavigationKeys read FDefaultNavigationKeys write SetDefaultNavigationKeys;
  89.   end;
  90.  
  91. const
  92.   AllNavigationKeys: TNavigationKeys = [nkEnter, nkUpDnArrows, nkCtrlTab];
  93.   K_ENTER = #13;
  94.   K_NULL  = #0;
  95.  
  96. procedure Register;
  97.  
  98. { csEZFormOptions is an access function so that
  99.   the local variable used to store the options
  100.   can be accessed from outside this unit.
  101. }
  102. function csEZFormOptions: TcsEZFormOptions;
  103.  
  104. implementation
  105.  
  106. var
  107.   { Define "class" variable for options }
  108.   EZFormOptions: TcsEZFormOptions;
  109.  
  110. procedure Register;
  111. begin
  112.   RegisterComponents('Samples', [TcsEZKeys]);
  113. end;
  114.  
  115. function csEZFormOptions: TcsEZFormOptions;
  116. begin
  117.   Result := EZFormOptions;
  118. end;
  119.  
  120. constructor TcsEZForm.Create(AOwner: TComponent);
  121. var EZKeysComponent: TcsEZKeys;
  122.     CurrentOnKeyDown: TKeyEvent;
  123.     CurrentOnKeyPress: TKeyPressEvent;
  124. begin
  125.   inherited Create(AOwner);
  126.  
  127.   { Save settings to allow restore }
  128.   FOldKeyPreview := KeyPreview;
  129.   FOldDefaultBtn := FindDefaultBtn;
  130.  
  131.   { Save the currently assigned event methods
  132.     (if any) for the methods to be handled
  133.     by the EZForm class.
  134.   }
  135.   CurrentOnKeyDown := OnKeyDown;
  136.   if Assigned(CurrentOnKeyDown) then
  137.     FOldOnKeyDown := OnKeyDown;
  138.   CurrentOnKeyPress := OnKeyPress;
  139.   if Assigned(CurrentOnKeyPress) then
  140.     FOldOnKeyPress := OnKeyPress;
  141.   { Re-assign to EZForm's event methods. }
  142.   OnKeyDown := FormKeyDown;
  143.   OnKeyPress := FormKeyPress;
  144.  
  145.   { Assign default navigation keys }
  146.   EZKeysComponent := FindEZKeys;
  147.   if (EZKeysComponent <> nil) then
  148.     SetNavigationKeys(EZKeysComponent.NavigationKeys)
  149.   else
  150.     { Assign default navigation keys only if
  151.       no value already assigned, e.g. in user's
  152.       own OnCreate event method.
  153.     }
  154.     if (NavigationKeys = []) then
  155.       SetNavigationKeys(EZFormOptions.DefaultNavigationKeys);
  156.  
  157.   if EZFormOptions.Enabled then
  158.   begin
  159.     KeyPreview := True;
  160.     { Turn off Default button if Enter in keys }
  161.     if (FOldDefaultBtn <> nil) and (nkEnter in NavigationKeys) then
  162.       FOldDefaultBtn.Default := False;
  163.   end;
  164.  
  165. end;
  166.  
  167. function TcsEZForm.FindEZKeys: TcsEZKeys;
  168. var AComponent: TComponent;
  169.     I: Integer;
  170. begin
  171.   Result := nil;
  172.   for I := 0 to ComponentCount - 1 do
  173.   begin
  174.     AComponent := Components[I];
  175.     if (AComponent is TcsEZKeys) then
  176.     begin
  177.       Result := AComponent as TcsEZKeys;
  178.       Break;
  179.     end;
  180.   end;
  181. end;
  182.  
  183. function TcsEZForm.FindDefaultBtn: TButton;
  184. var AComponent: TComponent;
  185.     I: Integer;
  186. begin
  187.   Result := nil;
  188.   for I := 0 to ComponentCount - 1 do
  189.   begin
  190.     AComponent := Components[I];
  191.     if ((AComponent is TButton) and ((AComponent as TButton).Default)) then
  192.     begin
  193.       Result := AComponent as TButton;
  194.       Break;
  195.     end;
  196.   end;
  197. end;
  198.  
  199. procedure TcsEZForm.FormKeyDown(Sender: TObject; var Key: Word;
  200.   Shift: TShiftState);
  201. begin
  202.   { Perform any user-assigned event method.
  203.     The user-assigned event method can set
  204.     Key to 0 to override the default handling.
  205.   }
  206.   if Assigned(FOldOnKeyDown) then
  207.     FOldOnKeyDown(Sender, Key, Shift);
  208.  
  209.   if EZFormOptions.Enabled then
  210.   begin
  211.     if not (Key = 0) then
  212.     begin
  213.       if (Key = VK_DOWN) or (Key = VK_UP) then
  214.       begin
  215.         if CanIntercept(nkUpDnArrows, ActiveControl) then
  216.           SelectNext(ActiveControl, (Key = VK_DOWN), True);
  217.       end
  218.       else
  219.       if (ssCtrl in Shift) and (Key = VK_TAB) and
  220.         CanIntercept(nkCtrlTab, ActiveControl) then
  221.       begin
  222.         { Set Key to 0 to stop spurious Tab keystrokes
  223.           going to Memo controls when Ctrl+Tab is held
  224.           down to cycle through all controls.
  225.         }
  226.         Key := 0;
  227.         SelectNext(ActiveControl, (not (ssShift in Shift)), True);
  228.       end;
  229.     end;
  230.   end;
  231. end;
  232.  
  233. procedure TcsEZForm.FormKeyPress(Sender: TObject; var Key: Char);
  234. begin
  235.   { Perform any user-assigned event method.
  236.     The user-assigned event method can set
  237.     Key to #0 to prevent the default handling.
  238.   }
  239.   if Assigned(FOldOnKeyPress) then
  240.     FOldOnKeyPress(Sender, Key);
  241.  
  242.   if EZFormOptions.Enabled then
  243.   begin
  244.     if not (Key = #0) then
  245.       if ((Key = K_ENTER) and CanIntercept(nkEnter, ActiveControl)) then
  246.       begin
  247.         Key := K_NULL; { consume the key }
  248.         SelectNext(ActiveControl, True, True);
  249.       end;
  250.   end;
  251. end;
  252.  
  253. function TcsEZForm.CanIntercept(KeyType: TNavigationKey; Ctrl: TControl): Boolean;
  254. begin
  255.   Result := False;
  256.   if EZFormOptions.Enabled and (KeyType in NavigationKeys) then
  257.     case KeyType of
  258.       { Note that in the current version of Delphi the WantReturns
  259.         property is only published for TMemo and not for TDBMemo,
  260.         even though they have the same ancestor.
  261.       }
  262.       nkEnter:      Result :=
  263.                       not (((Ctrl is TMemo) and (Ctrl as TMemo).WantReturns) or
  264.                            (Ctrl is TDBMemo)  or
  265.                            (Ctrl is TCustomDBGrid));
  266.       nkUpDnArrows: Result :=
  267.                       ((Ctrl is TEdit) or
  268.                        (Ctrl is TCustomMaskEdit));
  269.       nkCtrlTab:    Result := True;
  270.     else
  271.       Result := False;
  272.     end;
  273. end;
  274.  
  275. procedure TcsEZForm.SelectDefaultBtn;
  276. var DefaultBtnOnClick: TNotifyEvent;
  277. begin
  278.   if (OldDefaultBtn <> nil) then
  279.   begin
  280.     DefaultBtnOnClick := OldDefaultBtn.OnClick;
  281.     if Assigned(DefaultBtnOnClick) then
  282.       DefaultBtnOnClick(Self);
  283.   end;
  284. end;
  285.  
  286. procedure TcsEZForm.SetNavigationKeys(Value: TNavigationKeys);
  287. var HadEnter: Boolean;
  288.     HasEnter: Boolean;
  289. begin
  290.   HadEnter := (nkEnter in FNavigationKeys);
  291.   FNavigationKeys := Value;
  292.   if EZFormOptions.Enabled and (FOldDefaultBtn <> nil) then
  293.   begin
  294.     HasEnter := (nkEnter in FNavigationKeys);
  295.     if (HadEnter <> HasEnter) then
  296.       FOldDefaultBtn.Default := (not HasEnter);
  297.   end;
  298. end;
  299.  
  300. constructor TcsEZKeys.Create(AOwner: TComponent);
  301. begin
  302.   inherited Create(AOwner);
  303.   SetNavigationKeys(EZFormOptions.DefaultNavigationKeys);
  304. end;
  305.  
  306. procedure TcsEZKeys.SetNavigationKeys(Value: TNavigationKeys);
  307. begin
  308.   FNavigationKeys := Value;
  309. end;
  310.  
  311. constructor TcsEZFormOptions.Create;
  312. begin
  313.   inherited Create;
  314.   Init;
  315. end;
  316.  
  317. procedure TcsEZFormOptions.Init;
  318. begin
  319.   FEnabled := True;
  320.   FDefaultNavigationKeys := AllNavigationKeys;
  321. end;
  322.  
  323. procedure TcsEZFormOptions.Enable(Value: Boolean);
  324. var I: Integer;
  325. begin
  326.   FEnabled := Value;
  327.  
  328.   { Reflect new status in all open EZForms }
  329.   for I := 0 to Screen.FormCount - 1 do
  330.   begin
  331.     if (Screen.Forms[I] is TcsEZForm) then
  332.       with (Screen.Forms[I] as TcsEZForm) do
  333.       begin
  334.         if FEnabled then
  335.           KeyPreview := True
  336.         else
  337.         begin
  338.           KeyPreview := OldKeyPreview;
  339.         end;
  340.         if (OldDefaultBtn <> nil) then
  341.           OldDefaultBtn.Default := (not FEnabled) or not (nkEnter in NavigationKeys);
  342.       end;
  343.   end;
  344. end;
  345.  
  346. procedure TcsEZFormOptions.SetDefaultNavigationKeys(Value: TNavigationKeys);
  347. begin
  348.   FDefaultNavigationKeys := Value;
  349. end;
  350.  
  351. { Initialisation and cleanup }
  352. procedure FreeEZFormOptions; far;
  353. begin
  354.   EZFormOptions.Free;
  355. end;
  356.  
  357. initialization
  358.   EZFormOptions := TcsEZFormOptions.Create;
  359.   AddExitProc(FreeEZFormOptions);
  360. end.
  361.